package club.bigtian.method.util;

import club.bigtian.method.anno.MethodIgnore;
import club.bigtian.method.handler.BigFunctionAbstractProcessor;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.tree.JCTree;

import javax.tools.Diagnostic;
import java.util.*;
import java.util.stream.Collectors;

public class MethodUtils {


    public static Map<String, List<String>> getMethodParameters(JCTree.JCMethodDecl jcMethodDecl) {
        Map<String, List<String>> paramsMap = new HashMap<>();
        com.sun.tools.javac.util.List<JCTree.JCVariableDecl> list = jcMethodDecl.getParameters();
        if (!CollUtil.isEmpty(list)) {
            List<String> params = new ArrayList();
            Iterator var4 = list.iterator();
            while (var4.hasNext()) {
                JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) var4.next();
                params.add(jcVariableDecl.vartype.toString());
            }
            paramsMap.put(getMethodName(jcMethodDecl), params);
        }
        return paramsMap;
    }

    public static String[] getParameters(JCTree.JCMethodDecl jcMethodDecl) {
        String[] params = new String[0];
        com.sun.tools.javac.util.List<JCTree.JCVariableDecl> list = jcMethodDecl.getParameters();
        if (!CollUtil.isEmpty(list)) {
            params = new String[list.size()];
            for (int i = 0; i < list.size(); i++) {
                JCTree.JCVariableDecl jcVariableDecl = list.get(i);
                params[i] = jcVariableDecl.vartype.toString();
            }
        }
        Object returnType = jcMethodDecl.getReturnType();
        if (ObjectUtil.isNotNull(returnType) && !"void".equals(returnType.toString())) {
            params = Arrays.copyOf(params, params.length + 1);
            params[params.length - 1] = returnType.toString();
        }
        return params;
    }

    public static String getMethodName(JCTree.JCMethodDecl method) {
        return Objects.nonNull(method) ? method.getName().toString() : "";
    }

    public static List<JCTree.JCMethodDecl> getMethodByAnno(JCTree.JCClassDecl jcClassDecl, Class clazz) {
        return jcClassDecl.defs.stream()
                .filter((el) -> el.getKind().equals(Kind.METHOD))
                .map((el) -> (JCTree.JCMethodDecl) el)
                .filter(el -> !el.getModifiers().annotations.toString().contains(MethodIgnore.class.getSimpleName()))
                .filter((el) -> el.getModifiers().annotations.toString().contains(clazz.getSimpleName()))
                .collect(Collectors.toList());
    }


    public static List<JCTree.JCMethodDecl> getMethodAll(JCTree.JCClassDecl jcClassDecl, String[] filedType) {
        return jcClassDecl.defs.stream()
                .filter((el) -> el.getKind().equals(Kind.METHOD))
                .map((el) -> (JCTree.JCMethodDecl) el)
                .filter(el -> {
                    String methodType = el.getModifiers().annotations.toString();
                    String[] parameters = getParameters(el);
                    boolean flag = ArrayUtil.equals(parameters, filedType);
                    if (!flag) {
                        BigFunctionAbstractProcessor.messager.printMessage(Diagnostic.Kind.WARNING, StrUtil.format("The method {} parameters do not match the field", el.getName().toString()));
                        return false;
                    }
                    return !methodType.contains(MethodIgnore.class.getSimpleName()) && ObjectUtil.isNotNull(el.getReturnType());
                })
                .collect(Collectors.toList());
    }
}
